/* 
	@Copyright (c) 2007 by Denis Riabtchik. All rights reserved.@
	@Copyright (c) 2007 by Denis Riabtchik. All rights reserved. See license.txt and http://jgrouse.com for details@
	$Id: JGTask.java 596 2013-04-13 20:38:09Z denis.riabtchik@gmail.com $
*/
package jgrouse.jgdoc.ant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import jgrouse.jgdoc.DocParser;
import jgrouse.jgdoc.JGDocException;
import jgrouse.jgdoc.elements.DocManager;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;


public class JGTask extends Task
{
	public static final String FORMAT_XML = "XML";
	public static final String FORMAT_BIN = "BIN";
	
	private Project m_project;
	private List<FileSet> m_fileSets;
	private String m_output;
	private String m_encoding = "UTF-8";
	private boolean m_stopOnErrors = true;
	private boolean m_suppressGlobalWarnings = false;
	private String m_srcEncoding = "DEFAULT";
	private String m_srcUrl;
	private String m_outputFormat = FORMAT_XML;
	private String m_privatePrefix = null;
	private boolean m_suppressPrivates;

	public JGTask()
	{
		m_fileSets = new ArrayList<FileSet>();
	}
	
	public void setProject(Project pProject)
	{
		m_project = pProject;
	}
	
	public Project getProject()
	{
		return m_project;
	}
	
	public void addFileset(FileSet pFileSet)
	{
		m_fileSets.add(pFileSet);
	}

	@Override
	public void execute() throws BuildException
	{
		if (m_output == null)
		{
			throw new BuildException("Output directory not specified");
		}
		if (!(m_outputFormat.equals(FORMAT_BIN) || m_outputFormat.equals(FORMAT_XML)))
		{
			throw new BuildException("Invalid option for outputFormat:" + m_outputFormat);
		}
		File base = m_project.getBaseDir();
		File of = new File(m_output);
		File outputFile = of.isAbsolute()? of : new File(base, m_output);
		System.out.println("Building jGrouseDoc project file (" + m_outputFormat + ") " + outputFile.getAbsolutePath());
		DocManager dm = new DocManager();
		Map<String, String> props = new HashMap<String, String>();
		Iterator<Entry<String, Object>> iter =   m_project.getProperties().entrySet().iterator();
		while (iter.hasNext())
		{
			Entry<String, Object> e = iter.next();
			String key = e.getKey().toString();
			if (key.startsWith("jgdoc."))
			{
				props.put(key.substring("jgdoc.".length()), e.getValue().toString());
			}
		}
		if (m_srcUrl != null && !"not_defined".equals(m_srcUrl))
		{
			dm.setSrcUrl(m_srcUrl);
		}
		dm.setProperties(props);
		dm.setStopOnErrors(getStopOnErrors());
		
		dm.setSuppressGlobalWarnings(getSuppressGlobalWarnings());
		dm.setSuppressPrivates(getSuppressPrivates());
		String enc = getSrcEncoding();
		if ("DEFAULT".equalsIgnoreCase(enc))
		{
			enc = null;
		}
		
		for (FileSet fset : m_fileSets)
		{
			DocParser dp = new DocParser(dm);
			if (m_privatePrefix != null && m_privatePrefix.length() > 0 && !"not_specified".equalsIgnoreCase(m_privatePrefix))
			{
				dp.setPrivatePrefix(m_privatePrefix);
			}
			if (enc != null)
			{
				dp.setSrcEncoding(enc);
			}
			String dir = fset.getDir().getAbsolutePath();
			dir = dir.replace('\\', '/');
			if (dir.charAt(dir.length() - 1) != '/')
			{
				dir += '/';
			}
			DirectoryScanner ds = fset.getDirectoryScanner(getProject());
			String[] files = ds.getIncludedFiles();
			for (String f : files)
			{
				try
				{
					f = f.replace('\\', '/');
					dp.doExtract(f, dir);
				} catch (IOException e)
				{
					throw new BuildException(e);
				} catch (JGDocException e)
				{
					throw new BuildException(e);
				}
			}
		}
		dm.setEncoding(m_encoding);
		try
		{
			dm.postProcess();
		} catch (JGDocException e1)
		{
			String msg = e1.getMessage();
			if (e1.getFile() != null)
			{
				msg += " at " + e1.getFile() + ":" + e1.getLine();
			}
			throw new BuildException(msg);
		}
		List<String> msg = dm.getMessages();
		for (String s : msg)
		{
			log(s, Project.MSG_ERR);
		}
		FileOutputStream fis = null;
		
		try
		{
			fis = new FileOutputStream(outputFile);
			if (m_outputFormat.equals(FORMAT_XML))
			{
				String result = dm.toString();
				Writer w = new OutputStreamWriter(fis, Charset.forName(m_encoding));
				w.write(result);
				w.close();
			}
			else
			{
				@SuppressWarnings("resource")
				ObjectOutputStream oos = new ObjectOutputStream(fis);
				oos.writeObject(dm);
			}
			fis.close();
			fis = null;
		}
		catch (Exception e)
		{
			throw new BuildException(e);
		}
		finally
		{
			if (fis != null)
			{
				try
				{
					fis.close();
				} catch (IOException e)
				{
					throw new BuildException(e);
				}
			}
		}
	}

	public String getOutput()
	{
		return m_output;
	}

	public void setOutput(String pOutput)
	{
		m_output = pOutput;
	}

	public String getEncoding()
	{
		return m_encoding;
	}

	public void setEncoding(String pEncoding)
	{
		m_encoding = pEncoding;
	}

	public boolean getStopOnErrors()
	{
		return m_stopOnErrors;
	}

	public void setStopOnErrors(boolean pStopOnErrors)
	{
		m_stopOnErrors = pStopOnErrors;
	}

	public boolean getSuppressGlobalWarnings()
	{
		return m_suppressGlobalWarnings;
	}

	public void setSuppressGlobalWarnings(boolean pSuppressGlobalWarnings)
	{
		m_suppressGlobalWarnings = pSuppressGlobalWarnings;
	}

	public String getSrcEncoding()
	{
		return m_srcEncoding;
	}

	public void setSrcEncoding(String pSrcEncoding)
	{
		m_srcEncoding = pSrcEncoding;
	}

	public String getSrcUrl()
	{
		return m_srcUrl;
	}

	public void setSrcUrl(String pSrcUrl)
	{
		m_srcUrl = pSrcUrl;
	}

	public String getOutputFormat()
	{
		return m_outputFormat;
	}

	public void setOutputFormat(String pOutputFormat)
	{
		m_outputFormat = pOutputFormat.toUpperCase();
	}

	public String getPrivatePrefix()
	{
		return m_privatePrefix;
	}

	public void setPrivatePrefix(String pPrivatePrefix)
	{
		m_privatePrefix = pPrivatePrefix;
	}

	public boolean getSuppressPrivates()
	{
		return m_suppressPrivates;
	}

	public void setSuppressPrivates(boolean pSuppressPrivates)
	{
		m_suppressPrivates = pSuppressPrivates;
	}

		
}
